package com.itmatter.classifier.basicdb;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.enigmastation.classifier.ClassifierDataModelFactory;
import com.itmatter.classifier.util.ClassifierHibernateUtil;

import com.itmatter.classifier.domain.ClassifierCategory;
import com.itmatter.classifier.domain.ClassifierFeature;
import com.itmatter.classifier.domain.ClassifierFeatureId;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;

import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author Daniel Fisla, dfisla@itmatter.com, ITMATTER Inc., http://www.itmatter.com, Copyright 2010, LGPLv3
 */
public class HibernateClassifierDataModelFactory implements ClassifierDataModelFactory {

    private static final Logger logger = Logger.getLogger(HibernateClassifierDataModelFactory.class.getName());
    protected Map<String, Integer> categoryCountMap = new ConcurrentHashMap<String, Integer>();
    protected Map<String, Map<String, Integer>> featureMap = new ConcurrentHashMap<String, Map<String, Integer>>();

    private void initCategories() {
        logger.info("INIT-CLASSIFIER-CATEGORIES!");
        Transaction tx = null;
        try {
            Session session = ClassifierHibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.setFlushMode(FlushMode.COMMIT);

            Criteria criteria = session.createCriteria(ClassifierCategory.class);

            List rv = criteria.list();

            if (rv != null) {
                for (Iterator it = rv.iterator(); it.hasNext();) {
                    ClassifierCategory cat = (ClassifierCategory) it.next();
                    categoryCountMap.put(cat.getCategory(), cat.getCounts());
                }
            }
            tx.commit();

        } catch (HibernateException eh) {
            try {
                if (tx != null) {
                    tx.rollback();
                    logger.error("ROLLBACK!");
                }
            } catch (HibernateException eh2) {
            }

            logger.error(eh.getMessage(), eh);
        }
    }

    private void initFeatures() {

        logger.info("INIT-CLASSIFIER-FEATURES!");
        Transaction tx = null;
        try {
            Session session = ClassifierHibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.setFlushMode(FlushMode.COMMIT);

            Criteria criteria = session.createCriteria(ClassifierFeature.class);

            List rv = criteria.list();

            if (rv != null) {
                for (Iterator it = rv.iterator(); it.hasNext();) {
                    ClassifierFeature cat = (ClassifierFeature) it.next();

                    Map<String, Integer> cMap = new ConcurrentHashMap<String, Integer>();
                    ClassifierFeatureId fId = cat.getId();

                    cMap.put(fId.getCategory(), cat.getCounts());
                    featureMap.put(fId.getFeature(), cMap);
                }
            }
            tx.commit();
        } catch (HibernateException eh) {
            try {
                if (tx != null) {
                    tx.rollback();
                    logger.error("ROLLBACK!");
                }
            } catch (HibernateException eh2) {
            }

            logger.error(eh.getMessage(), eh);
        }
    }

    /**
     * 
     */
    public void deleteAllData() {

        logger.info("DELETE-ALL-DATA!");
        Transaction tx = null;
        try {
            Session session = ClassifierHibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.setFlushMode(FlushMode.COMMIT);

            String hqlCategories = String.format("delete from ClassifierCategory");
            Query queryCategories = session.createQuery(hqlCategories);

            int rv = queryCategories.executeUpdate();
            logger.info("DELETED CLS_CATEGORIES records: " + rv);


            tx.commit();
        } catch (HibernateException eh) {
            try {
                if (tx != null) {
                    tx.rollback();
                    logger.error("ROLLBACK!");
                }
            } catch (HibernateException eh2) {
            }

            logger.error(eh.getMessage(), eh);
        } finally {
            this.featureMap.clear();
        }

        try {
            Session session = ClassifierHibernateUtil.getSessionFactory().getCurrentSession();
            tx = session.beginTransaction();
            session.setFlushMode(FlushMode.COMMIT);

            String hqlFeatures = String.format("delete from ClassifierFeature");
            Query queryFeatures = session.createQuery(hqlFeatures);

            int rv = queryFeatures.executeUpdate();
            logger.info("DELETED CLS_FEATURES records: " + rv);

            tx.commit();
        } catch (HibernateException eh) {
            try {
                if (tx != null) {
                    tx.rollback();
                    logger.error("ROLLBACK!");
                }
            } catch (HibernateException eh2) {
            }

            logger.error(eh.getMessage(), eh);
        } finally {
            this.categoryCountMap.clear();
        }
    }

    /**
     * 
     */
    @SuppressWarnings("unchecked")
    public void init() {
        logger.info("INIT-CLASSIFIER-DATA-MODEL!");
        initCategories();
        initFeatures();
    }

    /**
     * Listener should handle updates
     */
    public void destroy() {
        logger.warn("Listener handles updates!");
    }

    /**
     * 
     * @return
     */
    public Map<String, Integer> getCategoryCountMap() {
        return categoryCountMap;
    }

    /**
     * 
     * @param feature
     * @return
     */
    public Map<String, Integer> getFeatureMap(String feature) {
        Map<String, Integer> fm = featureMap.get(feature);
        if (fm == null) {
            fm = new ConcurrentHashMap<String, Integer>();
            featureMap.put(feature, fm);
        }
        return fm;
    }
}
